#include "JointBoostingTest.h"
#include "MLTestTools.h"
#include "../Tools/randomGenerator.h"
#include "../Tools/ZLogManager.h"
#include "../Tools/XmlParser.h"
#include "ML_JointBoosting.h"
#include "ML_IOTools.h"
#include "../Scene/ZImageManager.h"
#include "../Scene/ZDataManager.h"
#include "ImageLoader.h"
#include "../Tools/FileTools.h"
#include "../Tools/ConfigManager.h"
#include "ImageFeature.h"
#include "ImageFeatureManager.h"
#include "ImageFragment.h"

#define USE_NEW_JOINT_BOOSTING 1
#define SAVE_FEATURE_IMAGE 1

GLOBAL_NAMESPACE_BEGIN

namespace MachineLearningTest
{
    //int     JBTest::dgOpts_.sampleSize = 500;
    //double  JBTest::dgOpts_.sampleCenters = {0, 1.0, 2.0};
    //int     JBTest::dgOpts_.sampleClass = sizeof(sampleCenters_)/sizeof(double);

    JBTest::DataGeneratorOptions JBTest::dgOpts_;

    const char* JBTest::runType[] = {
        "parameter",
        "test",
        "fragmentGen",
        "fragmentSave",
        "featureGen",
        "training",
        "trainingPrepareData",
        "trainingFeatureSel"
    };

    const char* JBTest::Attributes[] = {
        "type",
        "run",
        ///////////////////////////"parameter"
        "OutputFileName",
        "OutputLabelName",
        "SampleSize",
        "SampleClass",
        "SampleCenters",
        ///////////////////////////"test"
        "InputFileName",
        "InputLabelName",
        "OutputLabelName",
        "TrainingRound",
        "StepSize",
        "OutputModelName",
        //////////////////////////"fragmentGen"
        "InputFileName",
        "InputFolder",
        "SampleSize",
        "SaveImage",
        "OutputFolder",
        "OutputFragmentList",
        //////////////////////////"fragmentSave"
        "InputFileName",
        "InputFolder",
        //////////////////////////"featureGen"
        "InputFileName",
        "testImage",
        "OutputFolder",
        /////////////////////////"training"
        "InputFileName",
        "InputFolder",
        "InputFeatureGen",
        "InputFeatureFolder",
        "InputFeatureList",
        "InputLabelName",
        "TrainingRound",
        "StepSize",
        "OutputModelName",
        "OutputFolder",
        "OutputLabelName",
        /////////////////////////"trainingPrepareData"
        "InputFileName",
        "InputFolder",
        "InputFeatureGen",
        "SaveFeatureImg",
        "OutputFolder",
        "OutputModelFile",
        /////////////////////////"trainingFeatureSel"
        "InputFileName",
        "InputFolder",
        "InputFeatureGen",
        "InputFeatureFolder",
        "SelectRound"
    };

    int JBTest::getType(const std::string& type)
    {
        for (int i = 0; i < sizeof(runType) / sizeof(const char*); i++)
            if (type.compare(runType[i]) == 0)
                return RunTypes(i);
        return -1;
    }

    void JBTest::generateXMLTemplate(const char* fileName)
    {
        
    }

    void JBTest::generateTestData()
    {
        dgOpts_.bRun =  true;
        dgOpts_.outputFileName = "../../data/jb_test_data.txt";
        dgOpts_.outputPredName = "../../data/jb_test_data_label.txt";
        dgOpts_.sampleSize = 500;
        dgOpts_.sampleCenters.push_back(0);
        dgOpts_.sampleCenters.push_back(1);
        dgOpts_.sampleCenters.push_back(2);
        dgOpts_.sampleCenters.push_back(3);
        dgOpts_.classSize = dgOpts_.sampleCenters.size();

        const char* fileName = dgOpts_.outputFileName.c_str();
        int sampleSize = dgOpts_.sampleSize;
        int sampleClass= dgOpts_.classSize;
        std::vector<double> x, y;
        std::vector<double> tmp;
        
        Random_Generator::Start();
        for (int c = 0; c < sampleClass; c++)
        {
            tmp = Random_Generator::randomNormalVector(sampleSize, dgOpts_.sampleCenters[c]);
            x.insert(x.end(), tmp.begin(), tmp.end());
            tmp = Random_Generator::randomNormalVector(sampleSize,  dgOpts_.sampleCenters[c]);
            y.insert(y.end(), tmp.begin(), tmp.end());
        }

        std::ofstream fout(fileName);
        fout << x.size() << " " << 2 << "\n";
        for (int i = 0; i < x.size(); i++)
        {
            fout << x[i] << " " << y[i] << "\n";
        }
        fout.close();
        generatePredictLabel();
    }

    void JBTest::generatePredictLabel()
    {
        //const char* fileName = "../../data/jb_test_data_label.txt";
        //int sampleSize = dgOpts_.sampleSize;
        std::ofstream fout(dgOpts_.outputPredName);

        fout << dgOpts_.sampleSize*dgOpts_.classSize << " " << 1 << "\n";
        for (int c = 0; c < dgOpts_.classSize; c++)
        {
            for (int i = 0; i < dgOpts_.sampleSize; i++)
            {
                fout << c << "\n";
            }
        }

        fout.close();
    }

    double JBTest::validate(const Eigen::MatrixXi& input, const Eigen::MatrixXi& predMat)
    {
        int nSize = input.rows();
        int nDim  = input.cols();
        if (nSize != predMat.rows() || nSize==0 || nDim != predMat.cols() || nDim==0)
            return -1;

        int rightCount = 0;
        for (int i = 0; i < nSize; i++)
        {
            bool bSame = true;
            for (int j = 0; j < nDim; j++)
            {
                if (input(i, j)!=predMat(i, j))
                {
                    bSame = false;
                    break;
                }
            }
            if (bSame)
                rightCount++;
        }

        return 1.0*rightCount/nSize;
    }

    void JBTest::test0()
    {
        // load data from file
        const char* fileName = "jb_test_data.txt";
        const char* fileObjName = "jb_test_data.obj";
        Eigen::MatrixXd data;
        MLTestTools::loadDataFromFile(fileName, data);
        MLTestTools::saveDataAsObjFile(fileObjName, data);
    }

    void JBTest::test1()
    {
        const char* fileDataName = "../../data/jb_test_data.txt";
        const char* fileLabelName = "../../data/jb_test_data_label.txt";
        const char* fileOutName = "../../data/jb_test_data_predict.txt";
        Eigen::MatrixXd data;
        Eigen::MatrixXi labelMat;
        MLTestTools::loadDataFromFile(fileDataName, data);
        MLTestTools::loadDataFromFile(fileLabelName, labelMat);
        MLAlgorithms::JointBoosting jbAlgo;
        jbAlgo.setParams(50);
        jbAlgo.train(data, labelMat.col(0));
        Eigen::MatrixXi predictMat(data.rows(), 1);
        for (int i = 0; i < data.rows(); i++)
        {
            predictMat(i, 0) = jbAlgo.predict(data.row(i));
        }
        DebugLog << " Accuracy: " << validate(labelMat, predictMat);
        MLTestTools::saveDataToFile(fileOutName, predictMat);
    }

    void JBTest::saveJointBoostingToObjFile(const char* fileName, const MLAlgorithms::JointBoosting& jbAlgo)
    {
        std::ofstream fout(fileName);
        if (!fout)
        {
            DebugLog << "Cannot open the file " << fileName;
            return;
        }

        int nLeaner = jbAlgo.getLearnerSize();
        for (int i = 0; i < nLeaner; i++)
        {
            MLAlgorithms::DecisionStump* ds = (MLAlgorithms::DecisionStump*)jbAlgo.getWeakLearnerAt(i);
            const MLAlgorithms::DecisionStump::Parameters* param = ds->getParameters();

        }

        fout.close();
    }

    void JBTest::getDataFileNames(const char* inFileName, const std::string& folderName, std::vector<std::string>& fileNames)
    {
        std::ifstream fin(inFileName);
        if (!fin)
            return;

        int nSize = 0;
        fin >> nSize;
        std::string line;
        while (std::getline(fin, line))
        {
            if (line.empty()) continue;
            std::stringstream ss;
            ss << folderName << "/" << line;
            fileNames.push_back(ss.str());
        }
    }

    void JBTest::runParam(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return;

        std::string outputName(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_PARA_OUTPUT_FILENAME]));
        std::string outputPred(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_PARA_OUTPUT_PREDNAME]));
        int sampleSize = xml->getElementValueToInt(childName.c_str(), Attributes[XML_ML_JB_PARA_SAMPLE_SIZE]);
        int sampleClass = xml->getElementValueToInt(childName.c_str(), Attributes[XML_ML_JB_PARA_SAMPLE_CLASS]);
        std::vector<double> sampleCenters = xml->collectElementValusToDouble(
            childName.c_str(), Attributes[XML_ML_JB_PARA_SAMPLE_CENTERS]);
        if (sampleCenters.size()<sampleClass * 2)
        {
            DebugLog << "Wrong xml parameters.";
            return ;
        }

        DebugLog << "Begin to generate Testing Data..";
        std::vector<double> x, y;
        std::vector<double> tmp;

        Random_Generator::Start();
        for (int c = 0; c < sampleClass * 2; c += 2)
        {
            tmp = Random_Generator::randomNormalVector(sampleSize, sampleCenters[c]);
            x.insert(x.end(), tmp.begin(), tmp.end());
            tmp = Random_Generator::randomNormalVector(sampleSize, sampleCenters[c + 1]);
            y.insert(y.end(), tmp.begin(), tmp.end());
        }

        DebugLog << " Saving to file.. " << outputName;
        std::ofstream fout(outputName);
        if (!fout)
        {
            DebugLog << "Open file error." << outputName;
        }
        fout << x.size() << " " << 2 << "\n";
        for (int j = 0; j < x.size(); j++)
        {
            fout << x[j] << " " << y[j] << "\n";
        }
        fout.close();
        DebugLog << "Done.";

        DebugLog << "Begin to generate labeling Data..";
        DebugLog << " Saving to file.. " << outputPred;
        std::ofstream foutP(outputPred);

#if USE_NEW_JOINT_BOOSTING
        foutP << sampleSize*sampleClass << " " << sampleClass << "\n";
        Eigen::RowVectorXd label(sampleClass);
        for (int c = 0; c < sampleClass; c++)
        {
            label.setZero();
            label(c) = 1;
            for (int i = 0; i < sampleSize; i++)
            {
                foutP << label << "\n";
            }
        }
#else
        foutP << sampleSize*sampleClass << " " << 1 << "\n";
        for (int c = 0; c < sampleClass; c++)
        {
            for (int i = 0; i < sampleSize; i++)
            {
                foutP << c << "\n";
            }
        }
#endif
        foutP.close();
        DebugLog << "Done.";
    }

    void JBTest::runTest(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return;
        std::string inputFileName  (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TEST_INPUT_FILENAME]));
        std::string inputLabelName (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TEST_INPUT_LABELNAME]));
        std::string outputLabelName(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TEST_OUTPUT_LABELNAME]));
        std::string outputModelName(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TEST_OUTPUT_MODELNAME]));
        int roundM   = xml->getElementValueToInt(childName.c_str(), Attributes[XML_ML_JB_TEST_TRAINING_ROUND]);
        int stepSize = xml->getElementValueToInt(childName.c_str(), Attributes[XML_ML_JB_TEST_STEP_SIZE]);

        DebugLog << "Begin to train data.";
        Eigen::MatrixXd data;
        Eigen::MatrixXi labelMat;
        MLTestTools::loadDataFromFile(inputFileName.c_str(), data);
        MLTestTools::loadDataFromFile(inputLabelName.c_str(), labelMat);
        DebugLog << " data size:" << data.rows() << "*" << data.cols();
#if USE_NEW_JOINT_BOOSTING
        MLAlgorithms::MLJointBoosting jbAlgo;
        jbAlgo.setParams(roundM, stepSize);
        jbAlgo.train(data, labelMat);
        Eigen::MatrixXd evalMat;
        Eigen::MatrixXi predictMat = jbAlgo.predict(data, evalMat);
        MLAlgorithms::MLIOTools::saveToXMLFile(outputModelName.c_str(), &jbAlgo);
#else
        MLAlgorithms::JointBoosting jbAlgo;
        jbAlgo.setParams(roundM, stepSize);
        jbAlgo.train(data, labelMat.col(0));
        Eigen::MatrixXi predictMat(data.rows(), 1);
        Eigen::MatrixXd evalMat;
        jbAlgo.evaluate(data, evalMat);
        DebugLog << evalMat;
        for (int i = 0; i < data.rows(); i++)
        {
            predictMat(i, 0) = jbAlgo.predict(data.row(i));
        }
#endif
        DebugLog << " Accuracy: " << validate(labelMat, predictMat);
        //MLTestTools::saveDataToFile(outputLabelName.c_str(), predictMat);
        MLTestTools::saveDataToFile(outputLabelName.c_str(), evalMat);
        DebugLog << "Done.";
    }

    void JBTest::runFragGen(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return ;
        std::string inputFileName  (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FRAGGEN_INPUT_FILENAME]));
        std::string inputFolderName(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FRAGGEN_INPUT_FOLDER]));
        std::string outputFolder   (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FRAGGEN_OUTPUT_FOLDER]));
        std::string outputFragName (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FRAGGEN_OUTPUT_FRAGNAME]));
        int sampleSize = xml->getElementValueToInt    (childName.c_str(), Attributes[XML_ML_JB_FRAGGEN_SAMPLE_SIZE]);
        bool saveImage = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_FRAGGEN_SAVE_IMAGE]);
        std::vector<std::string> imageNames;
        getDataFileNames(inputFileName.c_str(), inputFolderName, imageNames);
        int nImageCount = imageNames.size();
        DataManager::getSingletonPtr()->clearImageData();
        for (size_t j = 0; j < nImageCount; j++)
        {
            ImageSpace::Image *ima = new ImageSpace::Image(ImageSpace::Image::IMAGE_Default);
            ima->loadImageFromFile(imageNames.at(j).c_str());
            DataManager::getSingletonPtr()->addImage(ima);
        }
        DebugLog << "Image count: " << DataManager::getSingletonPtr()->getImageCount();
        MLAlgorithms::ImageLoader* loader = new MLAlgorithms::ImageLoader(DataManager::getSingletonPtr());
        loader->init();
        loader->extractFragments(sampleSize, outputFolder);
        FileTools::checkDir(outputFolder.c_str());
        MLAlgorithms::MLIOTools::saveToXMLFile((outputFolder + outputFragName).c_str(), loader);
        if (saveImage)
        {
            DebugLog << "Begin to save images to disk..";
            // prepare folder
            std::string templFolder, maskFolder;
            std::string tempFolderPre, maskFolderPre;
            tempFolderPre = ConfigManager::getSingletonPtr()->getConfig()->read("templFolder", tempFolderPre);
            maskFolderPre = ConfigManager::getSingletonPtr()->getConfig()->read("maskFolder", maskFolderPre);
            templFolder   = outputFolder + tempFolderPre;
            maskFolder    = outputFolder + maskFolderPre;
            FileTools::checkDir(templFolder.c_str());
            FileTools::checkDir(maskFolder.c_str());
            DebugLog << " output folder: ";
            DebugLog << templFolder;
            DebugLog << maskFolder;

            // save images to disk
            nImageCount = DataManager::getSingletonPtr()->getImageCount();
            for (size_t j = 0; j < nImageCount; j++)
            {
                ImageSpace::Image* ima = DataManager::getSingletonPtr()->getImageById(j);
                if (!ima || ima->getType()==ImageSpace::Image::IMAGE_Default) continue;

                ima->saveImageToFile(ima->getFullPath().c_str());
            }
            DebugLog << "done.";
        }
        delete loader;
    }

    void JBTest::runFragSave(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return ;
        std::string inputFileName  (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FRAGSAV_INPUT_FILENAME]));
        MLAlgorithms::ImageLoader loader(DataManager::getSingletonPtr());
        MLAlgorithms::MLIOTools::loadFromXMLFile(inputFileName.c_str(), &loader);
    }

    void JBTest::runFeatureGen(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return ;
        std::string inputFileName(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FEATUREGEN_INPUT_FILENAME]));
        std::string testImageName(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FEATUREGEN_TEST_IMAGE]));
        std::string outputFolder (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_FEATUREGEN_OUTPUT_FOLDER]));
        MLAlgorithms::ImageLoader loader(DataManager::getSingletonPtr());
        MLAlgorithms::MLIOTools::loadFromXMLFile(inputFileName.c_str(), &loader);
        ImageSpace::Image* ima = DataManager::getSingletonPtr()->readImage(testImageName.c_str());
        std::vector<double> features;
        loader.extractFeaturesForImage(ima, features);

        FileTools::checkDir(outputFolder.c_str());
        std::string outputFImageFolder = outputFolder + "/fimage/";
        FileTools::checkDir(outputFImageFolder.c_str());
        std::stringstream ss;
        ImageFeatureManager::FeatureIterator fit = ImageFeatureManager::getSingletonPtr()->featureBeginIterator();
        while (fit!=ImageFeatureManager::getSingletonPtr()->featureEndIterator())
        {
            MLAlgorithms::ImageFeature* oneFeature = fit->second;
#if SAVE_FEATURE_IMAGE
            for (int count = 0; count < loader.getFragmentCount(); count ++)
            {
                const MLAlgorithms::ImageFragment* fragment = loader.getFragment(count);
                ss.str("");
                ss << outputFImageFolder << "fimage_" << oneFeature->getName() << "_" << fragment->getImage()->getName();
                cv::imwrite(ss.str(), oneFeature->getFeatureImage(count));
            }
#endif
            ss.str("");
            std::string name(fit->first->getName());
            ss << outputFolder << oneFeature->getName() << ".txt";
            oneFeature->saveFeatureToFile(ss.str().c_str());
            fit ++;
        }
    }

    void JBTest::runPrepareData(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return ;
        std::string inputFileName  (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_PRE_INPUT_FILENAME]));
        std::string inputFileFolder(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_PRE_INPUT_FOLDER]));
        std::string inputFeatureGen(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_PRE_INPUT_FEATUREGEN]));
        bool bSaveFeatureImg = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_TRAINING_PRE_SAVE_FEATUREIMG]);
        std::string outputFeaFolder(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_PRE_OUTPUT_FEATURE_FOLDER]));
        std::string outputModel    (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_PRE_OUTPUT_MODEL]));
        std::vector<std::string> dataFileNames;
        getDataFileNames(inputFileName.c_str(), inputFileFolder.c_str(), dataFileNames);
        if (inputFileName.empty())
        {
            DebugLog << "Input files are empty. Please check them.";
            DebugLog << "InputFileFolder: " << inputFileFolder;
            DebugLog << "inputFileName: " << inputFileName;
            return;
        }

        DataManager::getSingletonPtr()->clearImageData();
        // prepare the feature generator
        MLAlgorithms::ImageLoader loader(DataManager::getSingletonPtr());
        if (!MLAlgorithms::MLIOTools::loadFromXMLFile(inputFeatureGen.c_str(), &loader))
        {
            DebugLog << "Please check the input feature xml file.";
            DebugLog << inputFeatureGen;
            return;
        }

        // calculate features for each image

        // and save the features
        FileTools::checkDir(outputFeaFolder.c_str());
        std::string outputFTFolder(outputFeaFolder + "/feImages/");
        FileTools::checkDir(outputFTFolder.c_str());

        std::string outputFImageFolder = outputFeaFolder + "/fimage/";
        FileTools::checkDir(outputFImageFolder.c_str());

        std::vector<double> features;
        std::stringstream ss;
        DebugLog << "Begin to caculate features..";
        for (int i = 0; i < dataFileNames.size(); i++)
        {
            if (i % 20 == 0)
                std::cout << (char)13 << "processing "
                << i * 100 / dataFileNames.size() << "%";
            ImageSpace::Image* ima = DataManager::getSingletonPtr()->readImage(dataFileNames[i].c_str());
            loader.extractFeaturesForImage(ima, features);
            //save
            MLAlgorithms::ImageFeature* oneFeature = ImageFeatureManager::getSingletonPtr()->getFeature(ima);
            if (bSaveFeatureImg)
            {
                for (int count = 0; count < loader.getFragmentCount(); count++)
                {
                    const MLAlgorithms::ImageFragment* fragment = loader.getFragment(count);
                    ss.str("");
                    ss << outputFImageFolder << "fimage_" << oneFeature->getName() << "_" << fragment->getImage()->getName();
                    cv::imwrite(ss.str(), oneFeature->getFeatureImage(count));
                }
            }
            ss.str("");
            ss << outputFTFolder << oneFeature->getName() << ".txt";
            oneFeature->saveFeatureToFile(ss.str().c_str());
        }

        /*std::stringstream ss;
        ImageFeatureManager::FeatureIterator fit = ImageFeatureManager::getSingletonPtr()->featureBeginIterator();
        while (fit!=ImageFeatureManager::getSingletonPtr()->featureEndIterator())
        {
            MLAlgorithms::ImageFeature* oneFeature = fit->second;
            if (bSaveFeatureImg)
            {
                for (int count = 0; count < loader.getFragmentCount(); count ++)
                {
                    const MLAlgorithms::ImageFragment* fragment = loader.getFragment(count);
                    ss.str("");
                    ss << outputFImageFolder << "fimage_" << oneFeature->getName() << "_" << fragment->getImage()->getName();
                    cv::imwrite(ss.str(), oneFeature->getFeatureImage(count));
                }
            }
            ss.str("");
            std::string name(fit->first->getName());
            ss << outputFTFolder << oneFeature->getName() << ".txt";
            oneFeature->saveFeatureToFile(ss.str().c_str());
            fit ++;
        }*/

        //
    }

    void JBTest::runFeatureSel(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return ;
        std::string inputFileName  (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_FEASEL_INPUT_FILENAME]));
        std::string inputFileFolder(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_FEASEL_INPUT_FOLDER]));
        std::string inputFeatureGen(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_FEASEL_INPUT_FEATUREGEN]));
        std::string inputFeatFolder(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_FEASEL_INPUT_FEAGEN_FOLDER]));
        int round = xml->getElementValueToInt(childName.c_str(), Attributes[XML_ML_JB_TRAINING_FEASEL_ROUND]);

    }

    void JBTest::runTraining(FileTools::XmlParser* xml, const std::string& childName)
    {
        bool bRun = xml->getElementValueToBoolean(childName.c_str(), Attributes[XML_ML_JB_RUN]);
        if (!bRun) return ;
        std::string inputFileName  (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_INPUT_FILENAME]));
        std::string inputFileFolder(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_INPUT_FOLDER]));
        std::string inputFeatureGen(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_INPUT_FEATUREGEN]));
        std::string inputFeatFolder(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_INPUT_FEATURE_FOLDER]));
        std::string inputFeatList  (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_INPUT_FEATURE_LIST]));
        std::string inputLabelFile (xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_INPUT_LABEL_FILE]));
        int round    = xml->getElementValueToInt(childName.c_str(), Attributes[XML_ML_JB_TRAINING_ROUND]);
        int stepSize = xml->getElementValueToInt(childName.c_str(), Attributes[XML_ML_JB_TRAINING_STEP_SIZE]);
        std::string outputModel(xml->getElementValue(childName.c_str(), Attributes[XML_ML_JB_TRAINING_OUTPUT_MODEL]));

        // load feature list
        std::vector<std::string> featureList;
        getDataFileNames(inputFeatList.c_str(), inputFeatFolder.c_str(), featureList);
        // load them into memory
        for (int i = 0; i < featureList.size(); i++)
        {
            MLAlgorithms::ImageFeature* oneFea = new MLAlgorithms::ImageFeature(featureList[i]);
            if (!oneFea->loadFeatureFromFile(featureList[i].c_str()))
            {
                DebugLog << "Cannot load image feature: ";
                DebugLog << " " << featureList[i];
            }
            else
            {
                ImageFeatureManager::getSingletonPtr()->addFeature(oneFea);
            }
        }

        // load label file

        // generate training data
        int nDataSize = ImageFeatureManager::getSingletonPtr()->getFeatureCount();
        int nDataDim  = ImageFeatureManager::getSingletonPtr()->getFeatureDim();
        if (nDataSize<=0 || nDataDim<=0)
        {
            DebugLog << "Wrong input feature list.";
            return;
        }
        Eigen::MatrixXd trainData(nDataSize, nDataDim);
        ImageFeatureManager::FeatureIterator fit  = ImageFeatureManager::getSingletonPtr()->featureBeginIterator();
        ImageFeatureManager::FeatureIterator fend = ImageFeatureManager::getSingletonPtr()->featureEndIterator();
        for (int x=0; fit != fend ; fit++, x++)
        {
            std::vector<double> oneFeatureVec = fit->second->getFeatureVector();
            for (int y = 0; y < nDataDim; y++)
            {
                trainData(x, y) = oneFeatureVec[y];
            }
        }
    }

    void JBTest::run(const char* xmlFileName)
    {
        FileTools::XmlParser xml(xmlFileName);
        if (!xml.isValid()) return;
        std::vector<std::string> level1Names = xml.collectLevel1Nodes();
        for (int i = 0; i < level1Names.size(); i++)
        {
            std::string type(xml.getElementValue(level1Names[i].c_str(), "type"));
            int typeNum = getType(type);
            switch (typeNum)
            {
            case XML_ML_JB_RUN_PARAMETER:
                runParam(&xml, level1Names.at(i));
                break;
            case XML_ML_JB_RUN_TEST:
                runTest(&xml, level1Names.at(i));
                break;
            case XML_ML_JB_RUN_FRAGMENT_GEN:
                runFragGen(&xml, level1Names.at(i));
                break;
            case XML_ML_JB_RUN_FRAGMENT_SAVE:
                runFragSave(&xml, level1Names.at(i));
                break;
            case XML_ML_JB_RUN_FEATURE_GEN:
                runFeatureGen(&xml, level1Names.at(i));
                break;
            case XML_ML_JB_RUN_TRAINING:
                runTraining(&xml, level1Names.at(i));
                break;
            case XML_ML_JB_RUN_TRAINING_PREPAREDATA:
                runPrepareData(&xml, level1Names.at(i));
                break;
            case XML_ML_JB_RUN_TRAINING_FEA_SELECT:
                runFeatureSel(&xml, level1Names.at(i));
                break;
            }
        }
    }
}
GLOBAL_NAMESPACE_END